package com.rmi.discovery;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketTimeoutException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @author Dmitry
 */
public class JsonRmiFinder {
    public static final String jsonRmiId = UUID.randomUUID().toString();

    public Collection<InetAddress> find(int port) {
        // Find the server using UDP broadcast
        try {
            try (DatagramSocket c = new DatagramSocket()) {
                c.setBroadcast(true);

                byte[] sendData = ("DISCOVER_FUIFSERVER_REQUEST|" + jsonRmiId).getBytes();

                //Try the 255.255.255.255 first
                try {
                    DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, InetAddress.getByName("255.255.255.255"), port);
                    c.send(sendPacket);
                    //  System.out.println(getClass().getName() + ">>> Request packet sent to: 255.255.255.255 (DEFAULT)");
                } catch (IOException e) {
                }

                // Broadcast the message over all the network interfaces
                Enumeration interfaces = NetworkInterface.getNetworkInterfaces();
                while (interfaces.hasMoreElements()) {
                    NetworkInterface networkInterface = (NetworkInterface) interfaces.nextElement();

                    if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                        continue; // Don't want to broadcast to the loopback interface
                    }

                    for (InterfaceAddress interfaceAddress : networkInterface.getInterfaceAddresses()) {
                        InetAddress broadcast = interfaceAddress.getBroadcast();
                        if (broadcast == null) {
                            continue;
                        }

                        // Send the broadcast package!
                        try {
                            DatagramPacket sendPacket = new DatagramPacket(sendData, sendData.length, broadcast, port);
                            c.send(sendPacket);
                        } catch (IOException e) {
                        }

                        //   System.out.println(getClass().getName() + ">>> Request packet sent to: " + broadcast.getHostAddress() + "; Interface: " + networkInterface.getDisplayName());
                    }
                }

                //   System.out.println(getClass().getName() + ">>> Done looping over all network interfaces. Now waiting for a reply!");
                //Wait for a response
                Map<InetAddress, InetAddress> addresses = new HashMap<InetAddress, InetAddress>();

                byte[] recvBuf = new byte[15000];
                try {
                    while (true) {
                        DatagramPacket receivePacket = new DatagramPacket(recvBuf, recvBuf.length);
                        c.setSoTimeout(1000);
                        c.receive(receivePacket);
                        addresses.put(receivePacket.getAddress(), receivePacket.getAddress());
                    }
                } catch (SocketTimeoutException se) {

                }
                return addresses.values();
            }
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
}
